package com.sneakxy.mybatis.commons.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.UUID;

import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;

import com.sneakxy.mybatis.commons.dialect.Dialect;

/**
 * @author 潜行的青衣
 */
public class MybatisUtils {

	public static final char SQL_COLUMN_DELIMITER = '_';
	
	public static String buildSortSql(Sort sort, Dialect dialect) {
		if(sort != null) {
			StringBuilder result = new StringBuilder();
			Iterator<Order> it = sort.iterator();
			if(it.hasNext()) {
				result.append(" ORDER BY ");
				Order order = null;
				while(it.hasNext()) {
					order = it.next();
					result.append(String.format("%s %s", dialect != null ? dialect.formatColumnName(order.getProperty()) : order.getProperty(), order.getDirection()));
					if(it.hasNext()) {
						result.append(",");
					}
				}
			}
			return result.toString();
		}
		return StringUtils.EMPTY;
	}
	
	public static Field getField(Class<?> domainClass, String property) {
		if(StringUtils.contains(property, ".")) {
			String[] properties = StringUtils.split(property, "\\.");
			Field field = null;
			Class<?> loader = domainClass;
			for(String prop:properties) {
				field = FieldUtils.getDeclaredField(loader, prop, true);
				loader = field.getType();
			}
			return field;
		}
		return FieldUtils.getDeclaredField(domainClass, property, true);
	}
	
	public static Object getFieldValue(Class<?> domainClass, Object target, String property) throws IllegalAccessException {
		if(StringUtils.contains(property, ".")) {
			String[] properties = StringUtils.split(property, "\\.");
			Field field = null;
			Object value = target;
			Class<?> loader = domainClass;
			for(String prop:properties) {
				if(value == null) {
					break;
				}
				field = FieldUtils.getDeclaredField(loader, prop, true);
				loader = field.getType();
				value = FieldUtils.readField(field, value, true);
			}
			return value;
		}
		return FieldUtils.readField(target, property, true);
	}
	
	public static String getUUID() {
		return StringUtils.remove(UUID.randomUUID().toString(), "-");
	}
	
	public static <T extends Annotation> T getAnnotation(Class<?> loader, Field field, Class<T> annoType) {
		T result = field.getAnnotation(annoType);
		if(result == null) {
			Method method = MethodUtils.getMatchingMethod(loader, capitalize(field.getName(), "get"));
			if(method != null) {
				result = method.getAnnotation(annoType);
			}
		}
		return result;
	}
	
	public static String capitalize(String s, String prefix) {
		return new StringBuilder()
				.append(prefix)
				.append(StringUtils.capitalize(s)).toString();
	}
	
	public static Pageable getPageable(Object[] parameters) {
		for(Object parameter:parameters) {
			if(parameter instanceof Pageable) {
				return (Pageable) parameter;
			}
		}
		return null;
	}
	
	public static String toSqlColumnName(String name) {
		char[] array = name.toCharArray();
		StringBuilder builder = new StringBuilder(array.length);
		for(char ch:array) {
			if(CharUtils.isAsciiAlphaUpper(ch)) {
				builder.append(SQL_COLUMN_DELIMITER).append(Character.toLowerCase(ch));
			} else {
				builder.append(ch);
			}
		}
		return builder.toString();
	}
	
}
